import java.io.*;
import java.util.*;
import java.lang.*;
import java.math.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;

public class Exp {
    static final MyInteger sum = new MyInteger(0);
    static ReentrantLock lock = new ReentrantLock();
    static final int nThread = 100;

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Enter mode: ");
        String mode = in.nextLine();
        Thread[] threadList = new Thread[nThread];
        if (mode.equals("sync")) {
            System.out.println("Using sync mode...");
            for (int i = 1; i <= nThread; i++) {
                threadList[i - 1] = new Thread(new SyncTask(i));
                threadList[i - 1].start();
            }
        }
        else {
            System.out.println("Using async mode...");
            for (int i = 1; i <= nThread; i++) {
                threadList[i - 1] = new Thread(new Task());
                System.out.println("Thread NO." + i + " launched.");
                threadList[i - 1].start();
            }
        }
        for (int i = 0; i <= nThread - 1; i++) {
            try {
                threadList[i].join();
            }
            catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        System.out.println("sum = " + sum);
    }


}

class Task implements Runnable {
    public void run() {
        int tmp = Exp.sum.value;
        try {
            Thread.sleep(10);
        }
        catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        tmp = tmp + 1;
        Exp.sum.value = tmp;
    }
}

class SyncTaskUsingLock implements Runnable {
    int id;

    public SyncTaskUsingLock(int id) {
        this.id = id;
    }

    public void run() {
        Exp.lock.lock();
        try {
            System.out.println("Thread NO." + id + " entered critical region.");
            int tmp = Exp.sum.value;
            try {
                Thread.sleep(10);
            }
            catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            tmp = tmp + 1;
            Exp.sum.value = tmp;
            System.out.println("\tThread NO." + id + " out.");
        }
        finally {
            Exp.lock.unlock();
        }
    }
}

class SyncTask implements Runnable {
    int id;

    public SyncTask(int id) {
        this.id = id;
    }

    public void run() {
        synchronized (Exp.sum) {
            System.out.println("Thread NO." + id + " entered critical region.");
            int tmp = Exp.sum.value;
            try {
                Thread.sleep(10);
            }
            catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            tmp = tmp + 1;
            Exp.sum.value = tmp;
            System.out.println("\tThread NO." + id + " out.");
        }
    }
}